/**
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-09-C-0002, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * (c) 2009 The MITRE Corporation. All Rights Reserved.
 *
 * SPMIF to OPNET Translator
 * Author: ewalters
 * Created: 8:51:30 AM, Aug 15, 2007
 * MITRE Corporation
 */
package com.mitre.spmif2opnet.generation.ir;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import com.mitre.spmif2opnet.analysis.ast.Device;
import com.mitre.spmif2opnet.generation.OpnetGraphConverter;
import com.mitre.spmif2opnet.opnet.network.Attr;

/**
 * Represents the mapping between physical and logical processing nodes
 * NOTE: Look seriously at name vs. id for physical devices, etc. 
 *  do they have any place at all?
 */

public class PhysicalNode {
	/**
	 * Device associated with this node
	 */
	private Device _device;
	/**
	 *  Maps from list of resources to app names
	 */
	private Hashtable<String, Set<String>> _my_resources;
	/**
	 *  Is this the source device, i.e., do we have to hang the 
	 *  OPNET profile from this?
	 */
	private boolean _is_source;
	/**
	 *  This is an experiment for resource/device pairing
	 */
	private Hashtable<String, String> _other_resources;
	
	/**
	 * Constructor if we know it is not the source
	 * @param d the device
	 */
	public PhysicalNode(Device d) {
		this(d, false);
	}

	/**
	 * Default constructor
	 * @param d the device
	 * @param src are we a task source?
	 */
	public PhysicalNode(Device d, boolean src) {
		_device = d;
		_is_source = src;
		_my_resources = new Hashtable<String, Set<String>>();
		_other_resources = new Hashtable<String, String>();
	}
	
	/**
	 * Set us as the task source
	 */
	public void setAsSource() {
		_is_source = true;
	}

	/**
	 * Are we the task source?
	 * @return Well, are we?
	 */
	public boolean isSource() {
		return _is_source;
	}
	
	/**
	 * Add a resource mapped to this physical device
	 * @param res_name the resource
	 */
	public void addMyResource(String res_name) {
		_my_resources.put(res_name, new HashSet<String>());
	}

	/**
	 * Add an "other" resource
	 * @param res_name
	 * @param dev_name
	 */
	public void addOtherResource(String res_name, String dev_name) {
		_other_resources.put(res_name, dev_name);
	}
	
	/**
	 * Get our device id
	 * @return id the id
	 */
	public String getId() {
		return _device.getId();
	}
	
	/**
	 * Get the device model string
	 * @return the string
	 */
	public String getModel() {
		return _device.getModelName();
	}
		
	/**
	 * Convert the physical node to XML attributes
	 * NOTE: We currently do not do anything involved with device number or
	 *  characteristic - this needs to be addressed
	 * @param apps application names
	 * @param prof_names profile names
	 * @return the attribute list
	 */
	public List<Attr> getAttributes(Set<String> apps, Set<String> prof_names) {
		int i;
		List<Attr> attrs = new LinkedList<Attr>();
		// Fixed attrs
		attrs.add(OpnetGraphConverter.makeAttr("Application: ACE Tier Configuration", "Unspecified", "true"));
		attrs.add(OpnetGraphConverter.makeAttr("Application: Source Preferences", "None", "true"));
		attrs.add(OpnetGraphConverter.makeAttr("Application: Supported Services", "None", "true"));
		attrs.add(OpnetGraphConverter.makeAttr("Server: Modeling Method", "Detailed Server", "true"));

		// Add source extras
		if (_is_source) {
			attrs.add(OpnetGraphConverter.makeAttr("CPU Resource Parameters.count", "1"));
			attrs.add(OpnetGraphConverter.makeAttr("CPU Resource Parameters [0].Task Contention Mode", "Simulate Contention", "true"));
			attrs.add(OpnetGraphConverter.makeAttr("Application: Source Preferences.count", Integer.toString(_my_resources.size())));
			i = 0;
			for (String res_name : _my_resources.keySet()) {
				attrs.add(OpnetGraphConverter.makeAttr("Application: Source Preferences[" + Integer.toString(i) 
						+ "].Symbolic Name", res_name));
				++i;
			}
			i = 0;
			attrs.add(OpnetGraphConverter.makeAttr("Application: Supported Profiles.count", Integer.toString(prof_names.size())));				
			for (String pname : prof_names) {
				attrs.add(OpnetGraphConverter.makeAttr("Application: Supported Profiles ["
						+ Integer.toString(i) + "].Profile Name", pname));
				attrs.add(OpnetGraphConverter.makeAttr("Application: Supported Profiles ["
						+ Integer.toString(i) + "].Traffic Type", "All Discrete", "true"));
				++i;
			}
		} else {
			attrs.add(OpnetGraphConverter.makeAttr("Application: Supported Profiles", "None", "true"));			
		}
			i = 0;		 
			attrs.add(OpnetGraphConverter.makeAttr("Application: Destination Preferences.count", 
					Integer.toString(_other_resources.size() * apps.size())));
			for (String res_name : _other_resources.keySet()) {
				for (String app_name : apps) {
					String prefix = "Application: Destination Preferences [" + i + "].";
					attrs.add(OpnetGraphConverter.makeAttr(prefix + "Application", app_name));
					attrs.add(OpnetGraphConverter.makeAttr(prefix + "Symbolic Name", res_name));
					attrs.add(OpnetGraphConverter.makeAttr(prefix + "Actual Name.count", "1" ));
					attrs.add(OpnetGraphConverter.makeAttr(prefix + "Actual Name [0].Name", 
						"Logical Network." + _other_resources.get(res_name)));
					attrs.add(OpnetGraphConverter.makeAttr(prefix + "Actual Name [0].Selection Weight", "10" ));
					++i;
				}
			}

		attrs.add(OpnetGraphConverter.makeAttr("Server: Advanced Server Configuration.count", "1"));
		attrs.add(OpnetGraphConverter.makeAttr("Server: Advanced Server Configuration [0].Server Type", 
				_device.getLongModelName()));
		return attrs;
	}
	

}
